/*
 *  This file is part of AtlasMapper server and clients.
 *
 *  Copyright (C) 2012 Australian Institute of Marine Science
 *
 *  Contact: Gael Lafond <g.lafond@aims.org.au>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package au.gov.aims.colouriseimage.servlet;

import org.xml.sax.SAXParseException;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Utils {
	private static final Logger LOGGER = Logger.getLogger(Utils.class.getName());

	/**
	 * Create a valid URL from pretty much anything that can be found on the Web.
	 * See: http://stackoverflow.com/questions/724043/http-url-address-encoding-in-java
	 * @param urlStr The possibly invalid URL, as found on the Web.
	 * @return A valid URL.
	 */
	public static URL toURL(String urlStr) throws URISyntaxException, MalformedURLException {
		URI uri = null;

		// Add protocol, if missing
		int protocolSepIndex = urlStr.indexOf("://");
		int firstNotAscii = -1;

		Pattern pattern = Pattern.compile("[^a-zA-Z]");
		Matcher matcher = pattern.matcher(urlStr);
		if (matcher.find()) {
			firstNotAscii = matcher.start();
		}

		// Add the default "http" protocol if we have one of the 2 cases:
		// 1. Obvious case, no "://" found so there is not protocol.
		//     Example: www.google.com
		// 2. There is a "://", but it is after the first none ASCII char.
		//     Example: www.google.com?search=://
		if (protocolSepIndex < 0 || (firstNotAscii >= 0 && protocolSepIndex > firstNotAscii)) {
			urlStr = "http://" + urlStr;
		}

		try {
			// Try the URL as it is, it might be valid
			uri = new URI(urlStr);
		} catch(URISyntaxException ex) {
			// The URL is invalid
			URL rawUrl = new URL(urlStr);

			// The Scheme is the URL's protocol
			String scheme = rawUrl.getProtocol();

			// The Authority is the URL's host and the port number if needed
			int port = rawUrl.getPort();
			String authority = rawUrl.getHost() + (port > 0 ? ":"+port : "");

			// URI and URL agree to call this a path
			String path = rawUrl.getPath();

			// URI and URL agree to call this a query
			String query = rawUrl.getQuery();

			// The Fragment is the URL's reference, aka the anchor
			String fragment = rawUrl.getRef();

			uri = new URI(
					scheme,
					authority,
					path,
					query,
					fragment);
		}

		String cleanUrlStr = uri.toASCIIString();

		return new URL(cleanUrlStr);
	}

	public static String getExceptionMessage(Throwable ex) {
		return getExceptionMessage(ex, "No message available");
	}
	public static String getExceptionMessage(Throwable ex, String defaultMsg) {
		String msg = null;
		if (ex != null) {
			msg = ex.getMessage();

			// SAXParseException has handy values that do not shows on getMessage.
			if (ex instanceof SAXParseException) {
				SAXParseException saxEx = (SAXParseException)ex;
				if (Utils.isBlank(msg)) {
					// That should not happen
					msg = "Can not parse the XML document.";
				}
				msg += "\nline: " + saxEx.getLineNumber() + ", character: " + saxEx.getColumnNumber();
			}

			if (Utils.isBlank(msg)) {
				msg = getExceptionMessage(ex.getCause(), defaultMsg);
			}
		}
		if (msg == null || msg.isEmpty()) {
			msg = defaultMsg;
		}
		return msg;
	}

	public static boolean isBlank(String str) {
		return str==null || str.trim().isEmpty();
	}
	public static boolean isNotBlank(String str) {
		return !isBlank(str);
	}
}
